using System;
using System.Linq.Expressions;
using System.Windows.Controls.Primitives;
using FluentSilverlight.Commands;
using FluentSilverlight.Interceptors;

namespace FluentSilverlight.Binders
{
    public abstract class ButtonBaseBinder<THIS, TControl, TModel> : ContentControlBinder<THIS, TControl, TModel>
        where TModel : class
        where TControl : ButtonBase
    {
        private bool hideIfCannotExecuteCommand;

        protected ButtonBaseBinder(TModel model, TControl element)
            : base(model, element)
        {
        }

        public THIS OnClick<T>(Expression<Func<TModel, DelegateCommand<T>>> expression, bool hideIfCannotExecuteCommand)
        {
            this.hideIfCannotExecuteCommand = hideIfCannotExecuteCommand;
            return OnClick(expression);
        }

        public THIS OnClick<T>(Expression<Func<TModel, DelegateCommand<T>>> expression)
        {
            var command = PrepareCommand(expression, true);
            control.Click += (sender, e) => command.Execute(null);

            return thisInstance();
        }

        protected override void WireCommand(IFsCommand command)
        {
            base.WireCommand(command);

            command.CanExecuteChanged += (sender, e) => { control.IsEnabled = command.CanExecute(); };
            // initial setting
            control.IsEnabled = command.CanExecute();
        }

        protected override void BindVisibility(Expression<Func<TModel, object>> visibleExpression, IFsCommand command)
        {
            if (command == null) return;

            if (visibleExpression == null)
            {
                command.CanExecuteChanged += (sender, e) => SetVisibility(command);
                // needed such as that the initial setting is correct
                SetVisibility(command);
                return;
            }

            var binder = new CommandVisibilityBinder<TModel, TControl>(control, command,
                hideIfCannotExecuteCommand, model, visibleExpression);
        }

        private void SetVisibility(IFsCommand command)
        {
            var isVisible = command.CanExecute() || !hideIfCannotExecuteCommand;
            control.Visibility = isVisible.ToVisibility();
        }
    }
}